////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
//  File name:   LoaderDBA.cpp
//  Version:     v1.00
//  Created:     31/08/2006 by Alexey Medvedev.
//  Compilers:   Visual Studio.NET
//  Description: 
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"

#include <StringUtils.h>
#include "CryPath.h"

#include "ControllerPQ.h"
#include "ControllerOpt.h"
#include <CGFContent.h>
#include "LoaderDBA.h"




#define STORAGE_PADDING(bytes) 	(bytes)




void CGlobalHeaderDBA::CreateDatabaseDBA( const char *filename )
{
	MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_DBA, 0, filename);
	stack_string strPath = filename;
	CryStringUtils::UnifyFilePath(strPath);
	m_strFilePathDBA		= strPath.c_str();
	m_FilePathDBACRC32	= g_pCrc32Gen->GetCRC32( strPath.c_str() );
	m_nUsedAnimations		=	0;
}



void CGlobalHeaderDBA::LoadDatabaseDBA( const char *sForCharacter )
{
	MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_DBA, 0, m_strFilePathDBA.c_str()); 
	m_nTCount=0;
	if (m_pDatabaseInfoStreaming)
		return;
	if (m_IsRequested)
		return;
	m_IsRequested=1;

	_smart_ptr<IChunkFile>  pChunkFile = g_pI3DEngine->CreateChunkFile(true);
	if (!pChunkFile->Read( m_strFilePathDBA ))
	{
		ReportLoadError( sForCharacter,pChunkFile->GetLastError() );
		m_IsRequested=0;
		return;
	}

	// Load mesh from chunk file.
	if ((pChunkFile->GetFileHeader().Version != ChunkFileVersion) && (pChunkFile->GetFileHeader().Version != ChunkFileVersion_Align))
	{
		ReportLoadError( sForCharacter,"Bad DBA file version" );
		m_IsRequested=0;
		return;
	}

	if (pChunkFile->GetFileHeader().FileType != FileType_Geom) 
	{
		if (pChunkFile->GetFileHeader().FileType != FileType_Anim) 
		{
			ReportLoadError( sForCharacter,"Illegal File Type for .dba file" );
			m_IsRequested=0;
			return;
		}
	}

	if (m_pDatabaseInfoStreaming)
		CryFatalError("CryAnimation: memleak");

	m_pDatabaseInfoStreaming = new CInternalDatabaseInfo;
	m_pDatabaseInfo = m_pDatabaseInfoStreaming;

	if ( !LoadChunks(pChunkFile) )
	{
		delete m_pDatabaseInfo;
		m_pDatabaseInfo = 0;
		m_pDatabaseInfoStreaming = 0;
		ReportLoadError( sForCharacter,"Failed to load chunks" );
	}

	m_IsRequested=0;
	return;
}

//////////////////////////////////////////////////////////////////////////
bool CGlobalHeaderDBA::StartStreamingDBA( bool highPriority )
{
	//	LoadDatabaseDBA(0);
	//	return 1;

	if (m_pDatabaseInfoStreaming)
		return true;
	if (m_IsRequested)
		return true;
	m_IsRequested=1;

	// start streaming
	StreamReadParams params;



	params.dwUserData = eLoadFullData;

	params.ePriority = highPriority ? estpUrgent: estpNormal;
	params.nSize = 0;
	params.pBuffer = NULL;
	params.nLoadTime = 10000;
	params.nMaxLoadTime = 1000;

	g_pISystem->GetStreamEngine()->StartRead(eStreamTaskTypeAnimation, m_strFilePathDBA, this, &params);

	return true;
}

void CGlobalHeaderDBA::StreamOnComplete(IReadStream* pStream, unsigned nError)
{
	m_pDatabaseInfo = m_pDatabaseInfoStreaming;
}

void CGlobalHeaderDBA::StreamAsyncOnComplete(IReadStream* pStream, unsigned nError)
{
	DEFINE_PROFILER_FUNCTION();
	LOADING_TIME_PROFILE_SECTION(g_pISystem);
	MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_DBA, 0, m_strFilePathDBA.c_str()); 

	if(pStream->IsError())
	{ 
		g_pISystem->Warning( VALIDATOR_MODULE_ANIMATION,VALIDATOR_WARNING,	VALIDATOR_FLAG_FILE, m_strFilePathDBA,	"Failed to stream CAF-file" );
		return;
	}

	//--------------------------------------------------------------------------

	const char* buffer = (char*)pStream->GetBuffer();
	size_t size = pStream->GetBytesRead();
	_smart_ptr<IChunkFile> pChunkFile = g_pI3DEngine->CreateChunkFile(true);
	if (!pChunkFile->ReadFromMemBlock(buffer, size))
	{
		m_LastError = pChunkFile->GetLastError();
		return;
	}

	if (m_pDatabaseInfoStreaming)
		CryFatalError("CryAnimation: memleak1");

	// if we are currently deleting the database, we should not
	// go on here, because DeleteDatabaseDBA can already be messing with
	// CAF headers at this time
	if (m_bIsDeleting)
		return;

	m_pDatabaseInfoStreaming = new CInternalDatabaseInfo;
	m_pDatabaseInfo = 0;
	
	if ( LoadChunks(pChunkFile)==0 )
	{
		delete m_pDatabaseInfoStreaming;
		m_pDatabaseInfoStreaming = 0;
		ReportLoadError( m_strFilePathDBA.c_str(),"Failed to load chunks" );
	}

	m_IsRequested=0;

	if (g_pCharacterManager->m_pStreamingListener)
	{
		uint32 numHeadersCAF = g_AnimationManager.m_arrGlobalCAF.size();
		for(uint32 i=0; i < numHeadersCAF; i++)
		{
			GlobalAnimationHeaderCAF& rGAH = g_AnimationManager.m_arrGlobalCAF[i];
			if (rGAH.m_FilePathDBACRC32==m_FilePathDBACRC32)
			{
				int32 globalID = g_AnimationManager.GetGlobalIDbyFilePath_CAF(rGAH.GetFilePath());
				g_pCharacterManager->m_pStreamingListener->NotifyAnimLoaded(globalID);
			}
		}
	}
#ifndef _RELEASE	
	if (Console::GetInst().ca_DebugAnimUsageOnFileAccess)
		g_pCharacterManager->GetAnimationManager().DebugAnimUsage(0);
#endif
}

void CGlobalHeaderDBA::DeleteDatabaseDBA()
{
	// check if we are streaming
	if (!m_pDatabaseInfo && m_pDatabaseInfoStreaming)
		return;

	if (m_nUsedAnimations)
		return;

	// make sure that the DBA is GONE from the outside first
	// so it cannot be accessed from another thread while this is
	// running. Also we have to make sure to communicate that we are currently in the process of deleting
	// this DBA.
	CInternalDatabaseInfo* dbInfo = m_pDatabaseInfo;
	m_pDatabaseInfo = NULL;
	m_pDatabaseInfoStreaming = NULL;
	m_bIsDeleting = true;

	uint32 numHeadersCAF = g_AnimationManager.m_arrGlobalCAF.size();
	for (uint32 i=0; i<numHeadersCAF; i++)
	{
		GlobalAnimationHeaderCAF& rGAH = g_AnimationManager.m_arrGlobalCAF[i];
		if (rGAH.m_FilePathDBACRC32!=m_FilePathDBACRC32)
			continue;
		rGAH.m_nControllers=0;
		rGAH.m_arrController.clear();
		rGAH.m_arrControllerLookupVector.clear();
	}

	// now we can really delete it, since the data is no longer referenced through 
	// CAF headers
	if (dbInfo)
		delete dbInfo;

	if (g_pCharacterManager->m_pStreamingListener)
	{
		for (uint32 i=0; i<numHeadersCAF; i++)
		{
			GlobalAnimationHeaderCAF& rGAH = g_AnimationManager.m_arrGlobalCAF[i];
			if (rGAH.m_FilePathDBACRC32==m_FilePathDBACRC32)
			{
				int32 globalID = g_AnimationManager.GetGlobalIDbyFilePath_CAF(rGAH.GetFilePath());
				g_pCharacterManager->m_pStreamingListener->NotifyAnimUnloaded(globalID);
			}
		}
	}
#ifndef _RELEASE	
	if (Console::GetInst().ca_DebugAnimUsageOnFileAccess)
		g_pCharacterManager->GetAnimationManager().DebugAnimUsage(0);
#endif

	uint32 numLMGs = g_AnimationManager.m_arrGlobalLMG.size();
	for (uint32 l=0; l<numLMGs; l++)
		g_AnimationManager.m_arrGlobalLMG[l].m_nInitialized=0;

	m_bIsDeleting = false;
}

//--------------------------------------------------------------------------------

bool CGlobalHeaderDBA::InMemory()
{
	return (m_pDatabaseInfo!=0);
}

//--------------------------------------------------------------------------------

bool CGlobalHeaderDBA::LoadChunks(IChunkFile* pChunkFile)
{
	uint32 numChunck = pChunkFile->NumChunks();
	for (uint32 i=0; i<numChunck; i++)
	{
		const CHUNK_HEADER &hdr = pChunkFile->GetChunkHeader(i);
		switch (hdr.ChunkType)
		{

		case ChunkType_Controller:
			if (!ReadControllers( pChunkFile->GetChunk(i)) )
				return false;
			break;
		}
	}

	return true;
}


//--------------------------------------------------------------------------------------

bool CGlobalHeaderDBA::ReadControllers(IChunkFile::ChunkDesc *pChunkDesc)
{
	if (pChunkDesc->hdr.ChunkVersion == CONTROLLER_CHUNK_DESC_0900::VERSION)
		CryFatalError("CryAnimation: ReadController900 is not supported any more. Use DBAs generated with latest RC");
	if (pChunkDesc->hdr.ChunkVersion == CONTROLLER_CHUNK_DESC_0902::VERSION)
		CryFatalError("CryAnimation: ReadController902 is not supported any more. Use DBAs generated with latest RC");
	if (pChunkDesc->hdr.ChunkVersion == CONTROLLER_CHUNK_DESC_0903::VERSION)
		CryFatalError("CryAnimation: ReadController903 is not supported any more. Use DBAs generated with latest RC");
	if (pChunkDesc->hdr.ChunkVersion == CONTROLLER_CHUNK_DESC_0904::VERSION)
		CryFatalError("CryAnimation: ReadController904 is not supported any more. Use DBAs generated with latest RC");
	if (pChunkDesc->hdr.ChunkVersion == CONTROLLER_CHUNK_DESC_0905::VERSION)
		return ReadController905(pChunkDesc);
	CryFatalError("CryAnimation: unknown chunk-version in DBA file. Use DBAs generated with latest RC?");
	return true;
}


bool CGlobalHeaderDBA::ReadController905(IChunkFile::ChunkDesc *pChunkDesc  )
{
	LOADING_TIME_PROFILE_SECTION(g_pISystem);
	CONTROLLER_CHUNK_DESC_0905* pCtrlChunk = (CONTROLLER_CHUNK_DESC_0905*)pChunkDesc->data;

	uint16 *arrGlobalAnimID = new uint16[NUM_CAF_FILES];	
	if(arrGlobalAnimID == 0) 
	{
		g_pILog->UpdateLoadingScreen("error: could not allocate %d bytes", (int32)(sizeof(uint16)*NUM_CAF_FILES));
		return false;
	}
	for (uint32 i=0; i<NUM_CAF_FILES; i++)
		arrGlobalAnimID[i]=-1;

	m_pDatabaseInfoStreaming->m_iTotalControllers = 0;

	uint64 startedStatistics;
	if (Console::GetInst().ca_MemoryUsageLog)
	{
		CryModuleMemoryInfo info;
		CryGetMemoryInfoForModule(&info);
		startedStatistics = info.allocated - info.freed;
		g_pILog->UpdateLoadingScreen("ReadController905. Init. Memstat %li", (long int)(info.allocated - info.freed));
	}

	if (Console::GetInst().ca_MemoryUsageLog)
	{
		CryModuleMemoryInfo info;
		CryGetMemoryInfoForModule(&info);
		g_pILog->UpdateLoadingScreen("ReadController905. TracksResize. Memstat %li", (long int)(info.allocated - info.freed));
	}


	char *pData = (char*)(pCtrlChunk+1);
	char *pData2 = pData;

	uint32 totalAnims = pCtrlChunk->numAnims;
	uint32 keyTime = pCtrlChunk->numKeyTime;
	uint32 keyPos = pCtrlChunk->numKeyPos;
	uint32 keyRot = pCtrlChunk->numKeyRot;


	// Keytimes pointers
	uint16 * pktSizes = (uint16 *)pData;
	pData += keyTime * sizeof(uint16);
	uint32 * pktFormats = (uint32 *)pData;
	pData += (eBitset + 1) * sizeof(uint32);


	// Positions pointers
	uint16 * ppSizes = (uint16 *)pData;
	pData += keyPos * sizeof(uint16);
	uint32 * ppFormats = (uint32 *)pData;
	pData += eAutomaticQuat * sizeof(uint32);

	//Rotations pointers
	uint16 *prSizes = (uint16 *)pData;
	pData += keyRot * sizeof(uint16);
	uint32 *prFormats = (uint32 *)pData;
	pData += eAutomaticQuat * sizeof(uint32);

	uint32 * ktOffsets = (uint32 *)pData;
	pData += keyTime * sizeof(uint32);

	uint32 * pOffsets = (uint32 *)pData;
	pData += keyPos * sizeof(uint32);

	uint32 * rOffsets = (uint32 *)pData;
	pData += (keyRot+ 1) * sizeof(uint32);

	uint32 offset = (eAutomaticQuat + 1) * sizeof(uint32) + keyRot * sizeof(uint16);
	offset += (eAutomaticQuat + 1) * sizeof(uint32) + keyPos * sizeof(uint16);
	offset += (eBitset + 1) * sizeof(uint32) + keyTime * sizeof(uint16);

	offset += (keyRot + keyPos + keyTime + 1) * sizeof(uint32);

	ptrdiff_t diff = pData - pData2;
	pData += diff % 4 > 0 ? 4 - diff % 4 : 0;


	uint32 rCountSize = eAutomaticQuat + 1;
	std::vector<uint32> rCount(rCountSize);
	for (uint32 i = 1; i < rCountSize; ++i)
	{
		rCount[i] += rCount[i-1] + prFormats[i-1];
	}

	uint32 pCountSize = eAutomaticQuat + 1;
	std::vector<uint32> pCount(pCountSize);
	for (uint32 i = 1; i < pCountSize; ++i)
	{
		pCount[i] += pCount[i-1] + ppFormats[i-1];
	}

	uint32 ktCountSize = eBitset + 2;
	std::vector<uint32> ktCount(ktCountSize);
	for (uint32 i = 1; i < ktCountSize; ++i)
	{
		ktCount[i] += ktCount[i-1] + pktFormats[i-1];
	}

	uint32 totalAlloc= 0;
	uint32 curFormat = 0;

	while (curFormat + 1 < ktCountSize && ktCount[curFormat + 1] == 0)
		++curFormat;
	uint32 curSizeof = ControllerHelper::GetKeyTimesFormatSizeOf(curFormat);



	for (uint32 i = 0; i < keyTime; ++i)
	{
		while( i >= ktCount[curFormat + 1])
		{
			++curFormat;
			curSizeof = ControllerHelper::GetKeyTimesFormatSizeOf(curFormat);
		}
		totalAlloc += pktSizes[i] * curSizeof;
	}

	curFormat = 0;
	while (curFormat + 1 < pCountSize && pCount[curFormat + 1] == 0)
		++curFormat;

	curSizeof = ControllerHelper::GetPositionsFormatSizeOf(curFormat);



	for (uint32 i = 0; i < keyPos; ++i)
	{
		while( i >= pCount[curFormat + 1])
		{
			++curFormat;
			curSizeof = ControllerHelper::GetPositionsFormatSizeOf(curFormat);
		}

		totalAlloc += ppSizes[i] * curSizeof;
	}

	curFormat = 0;
	while (curFormat + 1 < rCountSize && rCount[curFormat + 1] == 0)
		++curFormat;

	curSizeof = ControllerHelper::GetRotationFormatSizeOf(curFormat);



	for (uint32 i = 0; i < keyRot; ++i)
	{
		while( i >= rCount[curFormat + 1])
		{
			++curFormat;
			curSizeof = ControllerHelper::GetRotationFormatSizeOf(curFormat);
		}
		totalAlloc += prSizes[i] * curSizeof;
	}

	totalAlloc = rOffsets[keyRot];
	totalAlloc += totalAlloc % 4 > 0 ? ( 4 - totalAlloc % 4) : 0;

	if (totalAlloc == 0) 
	{
		delete[] arrGlobalAnimID; 
		ReportLoadError( m_strFilePathDBA.c_str(), "Empty controller found" );
		return false;
	}

	// Xenon: Adding 16 bytes worth of padding to m_Storage to account for 16-byte overfetch using VMX
	m_pDatabaseInfoStreaming->m_Storage.resize( STORAGE_PADDING( totalAlloc ) );
	memcpy(&(m_pDatabaseInfoStreaming->m_Storage[0]), pData, totalAlloc);

	pData += totalAlloc;// - 2;// - 4;

	// set pointers to keytimes, positions, rotations
	if (Console::GetInst().ca_MemoryUsageLog)
	{
		CryModuleMemoryInfo info;
		CryGetMemoryInfoForModule(&info);
		g_pILog->UpdateLoadingScreen("ReadController905. All dynamic data resize. Memstat %li", (long int)(info.allocated - info.freed));
	}

	char * pDataBackup = pData;
	std::vector<CControllerInfo *> controllersOffsets(totalAnims,0 );

	for (uint32 i = 0; i < totalAnims; ++i)
	{

		uint16 strSize;// = pData;
		memcpy(&strSize, pData, sizeof(uint16));
		pData += sizeof(uint16);

#define BIG_STRING 1024

		if (strSize > BIG_STRING)
		{
			assert(0);
			delete[] arrGlobalAnimID; 
			return false;
		}
		char tmp[BIG_STRING];

		memset(tmp,0,BIG_STRING);
		memcpy(tmp, pData, strSize);

		//m_pDatabaseInfo->m_AnimationNames[i] = tmp;

		pData += strSize;


		int nGlobalAnimID = g_AnimationManager.CreateGAH_CAF(tmp);
		if (nGlobalAnimID<0)
			CryFatalError("GAH does not exist");
		arrGlobalAnimID[i]=nGlobalAnimID;

		GlobalAnimationHeaderCAF& rCAF = g_AnimationManager.m_arrGlobalCAF[nGlobalAnimID];
		if (rCAF.m_FilePathDBACRC32==0 && Console::GetInst().ca_UseIMG_CAF==1)
			CryFatalError("DBA/CAF mismatch");

		MotionParams905 info;
		memcpy(&info, pData, sizeof(info));
		pData += sizeof(info);

		if (rCAF.m_FilePathDBACRC32)
		{
			rCAF.m_nFlags			= info.m_nAssetFlags;
			
			rCAF.OnAssetCreated();

			rCAF.m_FilePathDBACRC32 = g_pCrc32Gen->GetCRC32(m_strFilePathDBA.c_str());
			//	m_pDatabaseInfo->m_SkinningInfo[i]->m_nCompression		= info.m_nCompression;
			int32 nStartKey				= info.m_nStart;
			int32 nEndKey					= info.m_nEnd;
			if (rCAF.m_nFlags & CA_ASSET_ADDITIVE)
				nStartKey++;
			int32 fTicksPerFrame  = TICKS_PER_FRAME;
			f32		fSecsPerTick		= SECONDS_PER_TICK;
			f32		fSecsPerFrame		= fSecsPerTick * fTicksPerFrame;
			rCAF.m_fStartSec = nStartKey * fSecsPerFrame;
			rCAF.m_fEndSec   = nEndKey   * fSecsPerFrame;
			if(rCAF.m_fEndSec<=rCAF.m_fStartSec)
				rCAF.m_fEndSec  = rCAF.m_fStartSec; //+(1.0f/30.0f);
			rCAF.m_fTotalDuration = rCAF.m_fEndSec - rCAF.m_fStartSec;

			rCAF.m_fMoveSpeed			= info.m_fMoveSpeed;
			rCAF.m_fTurnSpeed			= info.m_fTurnSpeed;
			rCAF.m_fAssetTurn			= info.m_fAssetTurn;
			rCAF.m_fDistance			= info.m_fDistance;
			rCAF.m_fSlope					= -info.m_fSlope;

			rCAF.m_StartLocation	= info.m_StartLocation;
			rCAF.m_EndLocation		= info.m_EndLocation;

			if ( fabsf(info.m_fTurnSpeed)>0.01f)
			{
				uint32 ddd=0;
			}
		}


		// footplants
		uint16 footplans;// = m_arrAnimations[i].m_FootPlantBits.size();
		memcpy(&footplans, pData, sizeof(uint16));
		pData += sizeof(uint16);
		pData += footplans;

		// 
		uint16 controllerInfo;// = m_arrAnimations[i].m_arrControlerInfo.size();
		memcpy(&controllerInfo, pData, sizeof(uint16));
		pData += sizeof(uint16);

		if (controllerInfo == 0)
			continue;

		CControllerInfo * pController = (CControllerInfo *)pData;
		controllersOffsets[i] = pController;

		pData += controllerInfo * sizeof(CControllerInfo);
		if (rCAF.m_FilePathDBACRC32)
			rCAF.m_arrController.resize(controllerInfo);
		rCAF.m_bEmpty=uint8(controllerInfo);

		m_pDatabaseInfoStreaming->m_iTotalControllers += controllerInfo;
	}

	m_pDatabaseInfoStreaming->m_pControllersInplace = new CControllerOptNonVirtual[m_pDatabaseInfoStreaming->m_iTotalControllers];
	uint32 controllersCount = 0;
	pData = pDataBackup;
	for (uint32 i = 0; i < totalAnims; ++i)
	{
		uint16 nGlobalAnimID=arrGlobalAnimID[i];
		if (nGlobalAnimID==0xffff)
			CryFatalError("Invalid GAH ID");
		GlobalAnimationHeaderCAF& rCAF = g_AnimationManager.m_arrGlobalCAF[nGlobalAnimID];
		uint32 numController = rCAF.m_bEmpty;

		CControllerInfo * pController = controllersOffsets[i];
		if (pController) 
		{
			for (uint32  t=0; t<numController; ++t)
			{
				uint32 p = pController[t].m_nPosTrack;
				uint32 r = pController[t].m_nRotTrack;
				uint32 pk = pController[t].m_nPosKeyTimeTrack;
				uint32 rk = pController[t].m_nRotKeyTimeTrack;
				uint32 id = pController[t].m_nControllerID;

				uint32 rotkt = (rk == ~0) ? eNoFormat : FindFormat(rk, ktCount);//formatKeyTimes[rk];
				uint32 rotk = (r == ~0) ? eNoFormat : FindFormat(r, rCount);//pFormatRot[r];
				uint32 poskt = (pk == ~0) ? eNoFormat : FindFormat(pk, ktCount);//formatKeyTimes[pk];
				uint32 posk = (p == ~0) ? eNoFormat : FindFormat(p, pCount);// pFormatPos[p];

				CControllerOptNonVirtual* pNewController = &m_pDatabaseInfoStreaming->m_pControllersInplace[controllersCount++];//( ControllerHelper::CreateController(rotk, rotkt, posk, poskt));
				pNewController->Init(rotk, rotkt, posk, poskt);
				pNewController->AddRef();// Controller will be deleted inplace!!!

				if (!pNewController)
				{
					delete[] arrGlobalAnimID; 
					return false;
				}

				if (r != ~0 && rk != ~0)
				{
					pNewController->SetRotationKeyTimes(pktSizes[rk], &m_pDatabaseInfoStreaming->m_Storage[ktOffsets[rk]]);
					pNewController->SetRotationKeys(prSizes[r], &m_pDatabaseInfoStreaming->m_Storage[rOffsets[r]]);//m_pDatabaseInfo->m_arrRotationTracks[r]->GetData());
				}

				if (p != ~0 && pk != ~0)
				{
					pNewController->SetPositionKeyTimes(pktSizes[pk], &m_pDatabaseInfoStreaming->m_Storage[ktOffsets[pk]]);
					pNewController->SetPositionKeys(ppSizes[p], &m_pDatabaseInfoStreaming->m_Storage[pOffsets[p]]);   ;//m_pDatabaseInfo->m_arrPositionTracks[p]->GetData());
				}

				pNewController->m_nControllerId = id;

				if (rCAF.m_FilePathDBACRC32)
					rCAF.m_arrController[t] = pNewController;
			}
		}

		if (rCAF.m_FilePathDBACRC32)
		{
			std::sort(rCAF.m_arrController.begin(),	rCAF.m_arrController.end(), AnimCtrlSortPred()	);
			rCAF.InitControllerLookup(numController);
			//		rCAF.m_FilePathDBACRC32 = nDBACRC32;
			rCAF.OnAssetCreated();
			rCAF.ClearAssetRequested();
			rCAF.ClearAssetNotFound();
			rCAF.m_nControllers  = numController;
			rCAF.m_nControllers2 = numController;
		}
	}

	if (Console::GetInst().ca_MemoryUsageLog)
	{ 
		CryModuleMemoryInfo info;
		CryGetMemoryInfoForModule(&info);
		g_pILog->UpdateLoadingScreen("ReadController903. Finished. Memstat %li", (long int)(info.allocated - info.freed));
		uint64 endStatistics = info.allocated - info.freed;
		g_AnimStatisticsInfo.m_iDBASizes += endStatistics - startedStatistics;
		g_pILog->UpdateLoadingScreen("Current DBA. Memstat %li", (long int)(endStatistics - startedStatistics)); 
		g_pILog->UpdateLoadingScreen("ALL DBAs %li", (long int)g_AnimStatisticsInfo.m_iDBASizes); 
	}

	m_pDatabaseInfoStreaming->Clear();
	delete[] arrGlobalAnimID; 
	return true;
}




//////////////////////////////////////////////////////////////////////////
void CGlobalHeaderDBA::ReportLoadError( const char *sForCharacter,const char *sReason )
{
	if (!m_bLoadFailed)
	{
		m_LastError = sReason;
		// Report loading error only once.
		m_bLoadFailed = true;
		if (Console::GetInst().ca_AnimWarningLevel > 2)
			AnimFileWarning( m_strFilePathDBA.c_str(),"Failed To Load Animation DBA %s (%s)",sForCharacter,sReason );
	}
}




const size_t CGlobalHeaderDBA::SizeOf_DBA() const
{
	size_t nSize=sizeof(CGlobalHeaderDBA);
	nSize += m_strFilePathDBA.capacity();
	nSize += m_LastError.capacity();
	if (m_pDatabaseInfo==0)
		return nSize;

	nSize += m_pDatabaseInfo->m_arrKeyTimesArray.get_alloc_size();
	nSize += m_pDatabaseInfo->m_arrRotationTracksArray.get_alloc_size();
	nSize += m_pDatabaseInfo->m_arrPositionTracksArray.get_alloc_size();

	nSize += m_pDatabaseInfo->m_arrKeyTimes.get_alloc_size();
	for (int i = 0; i < m_pDatabaseInfo->m_arrKeyTimes.size(); ++i)
		nSize += m_pDatabaseInfo->m_arrKeyTimes[i]->GetDataRawSize();

	nSize += m_pDatabaseInfo->m_arrRotationTracks.get_alloc_size();
	for (int i = 0; i < m_pDatabaseInfo->m_arrRotationTracks.size(); ++i)
		nSize += m_pDatabaseInfo->m_arrRotationTracks[i]->GetDataRawSize();

	nSize += m_pDatabaseInfo->m_arrPositionTracks.get_alloc_size();
	for (int i = 0; i < m_pDatabaseInfo->m_arrPositionTracks.size(); ++i)
		nSize += m_pDatabaseInfo->m_arrPositionTracks[i]->GetDataRawSize();

	nSize += m_pDatabaseInfo->m_Storage.get_alloc_size();
	nSize += m_pDatabaseInfo->m_iTotalControllers * sizeof(CControllerOptNonVirtual);//sizeof(IController_AutoPtr);	
//pSizer->AddObject(m_pControllersInplace, sizeof(CControllerOptNonVirtual)*m_iTotalControllers);
	return nSize;
}


void CGlobalHeaderDBA::GetMemoryUsage( ICrySizer *pSizer ) const
{
	pSizer->AddObject( m_pDatabaseInfo );		 
	pSizer->AddObject( m_LastError );		
}

CGlobalHeaderDBA::CGlobalHeaderDBA()
{
	m_pDatabaseInfo = 0;
	m_pDatabaseInfoStreaming = 0;
	m_FilePathDBACRC32 = 0;
	m_nUsedAnimations = 0;
	m_nTCount=0;
	m_bLoadFailed = false;
	m_bDBALock=0;
	m_nEmpty=0;
	m_IsRequested=0;
	m_bIsDeleting=false;
}
